package sr.myserver.config;


import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import sr.myserver.commons.Constants;
import sr.myserver.commons.Result;
import sr.myserver.commons.TokenManager;
import sr.myserver.service.LoginService;
import sr.myserver.vo.common.Basic;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

/**
 * 用户权限认证
 *
 * @author sirui
 */
@Slf4j
@Aspect
@Order(1)
public class Authorized {
    private static final List<String> URLS = new ArrayList<>();
    private static final String CLIENT_TYPE = "1";
    @Autowired
    LoginService loginService;

    static {
        URLS.add("/authorized");
    }

    @Pointcut("execution(* sr.myserver.controller..*(..))")
    private void webAuth() {
    }

    @Around("webAuth()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        String url = request.getServletPath();
        if (URLS.contains(url)) {
            return joinPoint.proceed();
        }
        String token = TokenManager.getCookie(request, response, Constants.AUTHORIZATION);
        Object[] objects = joinPoint.getArgs();
        if (!StringUtils.hasText(token)) {
            for (Object obj : objects) {
                if (obj instanceof Basic.Request) {
                    token = ((Basic.Request) obj).getToken();
                    break;
                }
            }
        }
        if (token == null) {
            return Result.fail("认证失败");
        }
        Claims claims;
        claims = JwtConfig.thinning(token);
        if (claims == null) {
            return Result.fail("认证失败");
        }
        long timeout = (System.currentTimeMillis() - claims.getIssuedAt().getTime()) / 1000 / 60;
        if (!CLIENT_TYPE.equals(claims.get(JwtConfig.CLIENT_TYPE))) {
            Basic.Response ret = tokenCheck(response, token, claims, timeout, 60, 30);
            if (ret != null) {
                return ret;
            }
        } else {
            Basic.Response ret = tokenCheck(response, token, claims, timeout, 24 * 60 * 3, 24 * 60 * 7);
            if (ret != null) {
                return ret;
            }
        }

        return joinPoint.proceed(objects);
    }

    /**
     * @param response http对象
     * @param token    token 串
     * @param curTime  token 创建了多长时间
     * @param timeout  token 过期时间
     * @param expTime  token 刷新时间
     * @return 状态码和消息
     */
    private Basic.Response tokenCheck(HttpServletResponse response, String token, Claims claims, long curTime, long timeout, int expTime) {
        if (curTime > timeout) {
            return Result.fail("00004", "登录已超时");
        }
        String userId = JwtConfig.getUserId(claims);
        if (timeout > expTime) {
            loginService.remove(userId);
            String jwtToken = JwtConfig.refresh(claims);
            TokenManager.setCookie(response, Constants.AUTHORIZATION, jwtToken);
            loginService.add(userId, jwtToken);

        } else if (!token.equalsIgnoreCase(loginService.get(userId))) {
            return Result.fail("00004", "登录已超时");
        }
        return null;
    }

}
